/* Soubor je ulozen v kodovani UTF-8.
 * Kontrola kódování: Příliš žluťoučký kůň úpěl ďábelské ódy. */

package cz.vse.adventura.po1715.xforv00_forejt.hra;

import cz.pecinovsky.english.pojj.adv_framework.game_gui.IListener;
import cz.pecinovsky.english.pojj.adv_framework.game_gui.IPlaceG;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static cz.vse.adventura.po1715.xforv00_forejt.hra.Texty.*;
import static cz.vse.adventura.po1715.xforv00_forejt.hra.Předmět.TEZKY;

/*******************************************************************************
 * Instance třídy {@code SprávceMístností} představují správce všech místností,
 * který je vytváří, umísťuje předměty, vytváří herní plán pospojováním
 * sousedních místností atd.
 *
 * @author    Vladimír Forejt
 * @version   0.00.000
 */
public class SprávceMístností
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    private static SprávceMístností správceMístností = new SprávceMístností();

//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

 /*****************************************************************************
 * Výchozí rozmístění předmětů
 */
    private final String[]
            DOMApředměty = {TEZKY+STUL, STOVKA, DVOUSTOVKA, DVOUSTOVKA, PAPIR, TEZKY+SKRINKA},
            MHORAKOVEpředměty = {},
            DLOUHApředměty = {TEZKY+KOS},
            AMBASADApředměty = {TUZKA, TEZKY+ZIDLE},
            FOTOKINOpředměty = {TEZKY+STUL},
            FINALNIpředměty = {},
            SKRINKApředměty = {PAS};

 /*****************************************************************************
 * Výchozí pozice místností na plánku
 */
    private final Point domaPosition = new Point(269, 106);
    private final Point mhorakovePosition = new Point(270, 304);
    private final Point dlouhaPosition = new Point(289, 206);
    private final Point ambasadaPosition = new Point(363, 387);
    private final Point fotokinoPosition = new Point(179, 386);
    private final Point skříňkaPosition = new Point(397, 100);
    private final Point finálníPosition = new Point(16, 16);

    //posluchači
    private final Collection<IListener<IPlaceG>> objectListeners =
                        new ArrayList<IListener<IPlaceG>>();
    private final Collection<IListener<IPlaceG>> neighborsListeners =
                        new ArrayList<IListener<IPlaceG>>();

//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
    private Map<String, Místnost> název2místnost =
                                  new HashMap<String, Místnost>();
    private Místnost aktuálníMístnost;
    private Místnost doma;
    private Místnost mhorakove;
    private Místnost dlouha;
    private Místnost ambasada;
    private Místnost fotokino;
    private Místnost skříňka;
    private Místnost finální;

//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================



//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * SprávceMístností bude jedináček, není jich potřeba více.
     *  Proto skrytý konstruktor
     */
    private SprávceMístností()
    {
        //TODO - nastavit jako jedináčka
        //název2místnost.clear();
        //VytvořMístnosti();
    }

/***************************************************************************
     * Vrátí odkaz na jediný SprávceMístností
     */
  static SprávceMístností getSprávceMístností()
    {
        return správceMístností;
    }

//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    /***************************************************************************
     * Vrátí odkaz na aktuální místnost,
     * tj. na místnost, v niž se pravé nachází hráč.
     *
     * @return Požadovaný odkaz
     */
    Místnost getAktuálníProstor()
    {
        return aktuálníMístnost;
    }

    /***************************************************************************
     * Nastaví aktuální prostor na požadovanou místnost
     * @param místnost
     */

    void setAktuálníProstor (Místnost místnost)
    {
        aktuálníMístnost = místnost;
        noticeNeighborsListeners();
        noticeObjectListeners();
    }

    /***************************************************************************
     * Vrátí odkaz na místnost podle zadaného názvu
     *
     * @param název místnost
     * @return Požadovaný odkaz
     */

    Místnost getMístnost(String název)
    {
        return název2místnost.get(název.toLowerCase());
    }

    /***************************************************************************
     * Vrátí kolekci odkazů na jednotlivé místnosti.
     *
     * @return Požadovaná kolekce
     */
//    @Override
    public Collection<? extends IPlaceG> getMístnosti()
     {
        return Collections.unmodifiableCollection(název2místnost.values());
     }

//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Inicialuzuje místnosti - smaže odkazy a znovu vytvoří
     */
    void inicializuj() {
        název2místnost.clear();
        vytvořMístnosti();
        noticeNeighborsListeners();
        noticeObjectListeners();
    }

    /***************************************************************************
     * Přidá zadaného posluchače do seznamu posluchačů,
     * které zpravuje o změně množiny předmětů v aktuální místnosti.
     *
     * @param listener Přihlašovaný posluchač
     */
    //@Override
    public void addObjectListener(IListener<IPlaceG> listener)
    {
         objectListeners.add(listener);
    }

     /***************************************************************************
     * Odebere zadaného posluchače ze seznamu posluchačů,
     * které zpravuje o změně množiny předmětů v aktuální místnosti.
     *
     * @param listener Odhlašovaný posluchač
     */
    //@Override
    public void removeObjectListener(IListener<IPlaceG> listener)
    {
         objectListeners.remove(listener);
    }

    /***************************************************************************
     * Přidá zadaného posluchače do seznamu posluchačů,
     * které zpravuje o změně množiny sousedů aktuální místnosti.
     *
     * @param listener Přihlašovaný posluchač
     */
//    @Override
    public void addNeighborsListener(IListener<IPlaceG> listener)
    {
         neighborsListeners.add(listener);
    }


    /***************************************************************************
     * Odebere zadaného posluchače ze seznamu posluchačů,
     * které zpravuje o změně množiny sousedů aktuální místnosti.
     *
     * @param listener Odhlašovaný posluchač
     */
//    @Override
    public void removeNeighborsListener(IListener<IPlaceG> listener)
    {
         neighborsListeners.remove(listener);
    }

    /***************************************************************************
     * Upozorní posluchače na změnu množiny předmětů
     */
    void noticeObjectListeners() {
        for (IListener<IPlaceG> listener : objectListeners) {
            listener.notice(aktuálníMístnost);
        }
    }
    /***************************************************************************
    * Upozorní posluchače na změnu množiny sousedů
    */
    void noticeNeighborsListeners() {
        for (IListener<IPlaceG> listener : neighborsListeners) {
            listener.notice(aktuálníMístnost);
        }
    }

//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================



//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Vytvoří na začátku místnosti a jejich sousedy
     */
    private void vytvořMístnosti()
    {
        doma = new Místnost (DOMA, DOMApopis, DOMApředměty, domaPosition);
        mhorakove = new Místnost(MHORAKOVE, MHORAKOVEpopis, MHORAKOVEpředměty,
                                                            mhorakovePosition);
        dlouha = new Místnost(DLOUHA, DLOUHApopis, DLOUHApředměty, dlouhaPosition);
        ambasada = new Místnost(AMBASADA, AMBASADApopis, AMBASADApředměty,
                                                        ambasadaPosition);
        fotokino = new Místnost(FOTOKINO, FOTOKINOpopis, FOTOKINOpředměty,
                                                          fotokinoPosition );
        skříňka = new Místnost (SKRINKA, SKRINKApopis, SKRINKApředměty,
                                                        skříňkaPosition);
        finální = new Místnost (FINALNI, FINALNIpopis, FINALNIpředměty,
                                                        finálníPosition);

        //Jména místností se uloží malými písmeny
        název2místnost.put(DOMA.toLowerCase(), doma);
        název2místnost.put(MHORAKOVE.toLowerCase(), mhorakove);
        název2místnost.put(DLOUHA.toLowerCase(), dlouha);
        název2místnost.put(AMBASADA.toLowerCase(), ambasada);
        název2místnost.put(FOTOKINO.toLowerCase(), fotokino);
        název2místnost.put(SKRINKA.toLowerCase(), skříňka);
        název2místnost.put(FINALNI.toLowerCase(), finální);

        //vloží se postavy do místností

        Postava úředník = new Postava (TEZKY+UREDNIK, VIZUM, UREDNIKchce );
        ambasada.polož(úředník);
        Postava prodavačka = new Postava (TEZKY+PRODAVACKA, FOTOGRAFIE, PRODAVACKAchce);
        fotokino.polož(prodavačka);

        //Nastavení sousedních místností
        finální.setSoused(doma);

        doma.setSoused(dlouha);

        dlouha.setSoused(doma);
        dlouha.setSoused(mhorakove);

        mhorakove.setSoused(ambasada);
        mhorakove.setSoused(fotokino);
        mhorakove.setSoused(dlouha);

        ambasada.setSoused(mhorakove);

        fotokino.setSoused(mhorakove);

        //nastaví aktuálníMístnost na začátku hry na "doma"
        aktuálníMístnost = doma;

    }

//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTY A METODA MAIN =======================================================
//
//     /***************************************************************************
//      * Testovací metoda.
//      */
//     public static void test()
//     {
//         SprávceMístností instance = new SprávceMístností();
//     }
//     /** @param args Parametry příkazového řádku - nepoužívané. */
//     public static void main(String[] args)  {  test();  }
}
